home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
ue312src.zip
/
REPLACE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-20
|
12KB
|
519 lines
/*
* replace.c
*
* Functions, formerly in search.c, which handle the search and replace
* functionality.
*/
#include <stdio.h>
#include "estruct.h"
#include "eproto.h"
#include "edef.h"
#include "elang.h"
static int replen; /* length of replacement string */
/*
* sreplace -- Search and replace.
*/
int PASCAL NEAR sreplace(f, n)
int f; /* default flag */
int n; /* # of repetitions wanted */
{
return (replaces(FALSE, f, n));
}
/*
* qreplace -- search and replace with query.
*/
int PASCAL NEAR qreplace(f, n)
int f; /* default flag */
int n; /* # of repetitions wanted */
{
return (replaces(TRUE, f, n));
}
/*
* replaces -- Search for a string and replace it with another
* string. Query might be enabled (according to kind).
*/
int PASCAL NEAR replaces(kind, f, n)
int kind; /* Query enabled flag */
int f; /* default flag */
int n; /* # of repetitions wanted */
{
register int status; /* success flag on pattern inputs */
register int nummatch; /* number of found matches */
int numsub; /* number of substitutions */
int nlflag; /* last char of search string a <NL>? */
int nlrepl; /* was a replace done on the last line? */
char c; /* input char for query */
LINE *origline; /* original "." position */
int origoff; /* and offset (for . query option) */
LINE *lastline; /* position of last replace and */
int lastoff; /* offset (for 'u' query option) */
int oldmatchlen; /* Closure may alter the match length.*/
static char *oldpatmatch = NULL; /* allocated memory for un-do.*/
/*
* Don't allow this command if we are
* in read only mode.
*/
if (curbp->b_mode & MDVIEW)
return(rdonly());
/* Check for negative repetitions.
*/
if (f && n < 0)
return(FALSE);
/* Ask the user for the text of a pattern.
*/
if ((status = readpattern(kind? TEXT85: TEXT84, &pat[0], TRUE)) != TRUE)
/* "Replace" */
/* "Query replace" */
return(status);
/* Ask for the replacement string, and get its length.
*/
if ((status = readpattern(TEXT86, &rpat[0], FALSE)) == ABORT)
/* "with" */
return(status);
/* Set up flags so we can make sure not to do a recursive
* replace on the last line.
*/
nlflag = (pat[matchlen - 1] == '\r');
nlrepl = FALSE;
/* Save original . position, reset the number of matches and
* substitutions, and scan through the file.
*/
origline = curwp->w_dotp;
origoff = curwp->w_doto;
numsub = 0;
nummatch = 0;
lastline = (LINE *)NULL;
mmove_flag = FALSE; /* disable mouse move events */
while ( (f == FALSE || n > nummatch) &&
(nlflag == FALSE || nlrepl == FALSE) ) {
/* Search for the pattern.
* If we search with a regular expression,
* matchlen is reset to the true length of
* the matched string.
*/
#if MAGIC
if (magical && (curwp->w_bufp->b_mode & MDMAGIC)) {
if (!mcscanner(FORWARD, PTBEG, 1))
break;
}
else
#endif
if (!scanner(FORWARD, PTBEG, 1))
break; /* all done */
++nummatch; /* Increment # of matches */
/* Check if we are on the last line.
*/
nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
/* Check for query.
*/
if (kind) {
/* Get the query.
*/
pprompt: mlrquery();
qprompt:
/* Show the proposed place to change, and
* update the position on the modeline if needed.
*/
if (posflag)
upmode();
update(TRUE);
c = tgetc(); /* and input */
mlerase(); /* and clear it */
/* And respond appropriately.
*/
switch (c) {
#if FRENCH
case 'o': /* oui, substitute */
case 'O':
#endif
case 'y': /* yes, substitute */
case 'Y':
case ' ':
break;
case 'n': /* no, onward */
case 'N':
forwchar(FALSE, 1);
continue;
case '!': /* yes/stop asking */
kind = FALSE;
break;
case 'u': /* undo last and re-prompt */
case 'U':
/* Restore old position.
*/
if (lastline == (LINE *)NULL) {
/* There is nothing to undo.
*/
TTbeep();
goto pprompt;
}
curwp->w_dotp = lastline;
curwp->w_doto = lastoff;
lastline = NULL;
lastoff = 0;
/* Delete the new string,
* restore the old match.
*/
backchar(FALSE, replen);
status = delins(replen, oldpatmatch, FALSE);
if (status != TRUE) {
mmove_flag = TRUE;
return(status);
}
/* Record one less substitution,
* backup, save our place, and
* reprompt.
*/
--numsub;
backchar(FALSE, oldmatchlen);
matchlen = oldmatchlen;
matchline = curwp->w_dotp;
matchoff = curwp->w_doto;
continue;
case '.': /* abort! and return */
/* restore old position */
curwp->w_dotp = origline;
curwp->w_doto = origoff;
curwp->w_flag |= WFMOVE;
case BELL: /* abort! and stay */
mlwrite(TEXT89);
/* "Aborted!" */
mmove_flag = TRUE;
return(FALSE);
default: /* bitch and beep */
TTbeep();
case '?': /* help me */
mlwrite(TEXT90);
/*"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: "*/
goto qprompt;
} /* end of switch */
} /* end of "if kind" */
/* if this is the point origin, flag so we a can reset it */
if (curwp->w_dotp == origline) {
origline = NULL;
lastline = lback(curwp->w_dotp);
}
/* Delete the sucker, and insert its
* replacement.
*/
#if MAGIC
status = delins(matchlen, &rpat[0], rmagical);
#else
status = delins(matchlen, &rpat[0], FALSE);
#endif
if (origline == NULL) {
origline = lforw(lastline);
origoff = 0;
}
if (status != TRUE) {
mmove_flag = TRUE;
return(status);
}
numsub++; /* increment # of substitutions */
/* Save our position, the match length, and the string
* matched if we are query-replacing, as we may undo
* the replacement. If we are not querying, check to
* make sure that we didn't replace an empty string
* (possible in MAGIC mode), because we'll infinite loop.
*/
if (kind) {
lastline = curwp->w_dotp;
lastoff = curwp->w_doto;
oldmatchlen = matchlen; /* Save the length for un-do.*/
#if (TURBO || ZTC) && (DOS16M == 0)
/* For compilers with reallocs that handle
* NULL pointers.
*/
if ((oldpatmatch = realloc(oldpatmatch, matchlen + 1)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
mmove_flag = TRUE;
return(ABORT);
}
#else
if (oldpatmatch != NULL)
free(oldpatmatch);
if ((oldpatmatch = malloc(matchlen + 1)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
mmove_flag = TRUE;
return(ABORT);
}
#endif
strcpy(oldpatmatch, patmatch);
}
else if (matchlen == 0) {
mlwrite(TEXT91);
/* "Empty string replaced, stopping." */
mmove_flag = TRUE;
return(FALSE);
}
}
/* And report the results.
*/
mlwrite(TEXT92, numsub);
/* "%d substitutions" */
mmove_flag = TRUE;
return(TRUE);
}
/*
* mlrquery -- The prompt for query-replace-string.
*/
VOID PASCAL NEAR mlrquery()
{
register int tcol;
#if MAGIC
register RMC *rmcptr;
#endif
mlwrite(TEXT87);
/* "Replace '" */
tcol = echostring(patmatch, strlen(TEXT87), NPAT/2);
mlputs(TEXT88);
/* "' with '" */
tcol += strlen(TEXT88);
#if MAGIC
if (rmagical && (curwp->w_bufp->b_mode & MDMAGIC)) {
rmcptr = &rmcpat[0];
while (rmcptr->mc_type != MCNIL && tcol < NPAT - 8) {
if (rmcptr->mc_type == LITSTRING)
tcol = echostring(rmcptr->u.rstr, tcol, NPAT - 8);
else if (rmcptr->mc_type == DITTO)
tcol = echostring(patmatch, tcol, NPAT - 8);
else
tcol = echostring(grpmatch[rmcptr->u.group_no],
tcol, NPAT - 8);
rmcptr++;
}
}
else
#endif
echostring(rpat, tcol, NPAT - 8);
mlputs("'? ");
}
/*
* delins -- Delete a specified length from the current point
* then either insert the string directly, or make use of
* replacement meta-array.
*/
int PASCAL NEAR delins(dlength, instr, use_rmc)
int dlength;
char *instr;
int use_rmc;
{
register int status;
register char *rstr;
#if MAGIC
register RMC *rmcptr;
#endif
replen = 0;
/* Zap what we gotta,
* and insert its replacement.
*/
if ((status = ldelete((long) dlength, FALSE)) != TRUE)
mlwrite(TEXT93);
/* "%%ERROR while deleting" */
else
#if MAGIC
if (use_rmc && (curwp->w_bufp->b_mode & MDMAGIC)) {
rmcptr = &rmcpat[0];
while (rmcptr->mc_type != MCNIL && status == TRUE) {
if (rmcptr->mc_type == LITSTRING)
status = linstr(rstr = rmcptr->u.rstr);
else if (rmcptr->mc_type == DITTO)
status = linstr(rstr = patmatch);
else
status = linstr(rstr = fixnull(grpmatch[rmcptr->u.group_no]));
replen += strlen(rstr);
rmcptr++;
}
}
else
#endif
{
status = linstr(instr);
replen = strlen(instr);
}
return (status);
}
/*
* rmcstr -- Set up the replacement 'magic' array. Note that if there
* are no meta-characters encountered in the replacement string,
* the array is never actually created - we will just use the
* character array rpat[] as the replacement string.
*/
int PASCAL NEAR rmcstr()
{
RMC *rmcptr;
char *patptr;
int pchr;
int status = TRUE;
int mj;
patptr = (char *)&rpat[0];
rmcptr = &rmcpat[0];
mj = 0;
rmagical = FALSE;
while (*patptr && status == TRUE) {
switch (*patptr) {
case MC_DITTO:
/* If there were non-magical characters in
* the string before reaching this character
* plunk it in the replacement array before
* processing the current meta-character.
*/
if (mj != 0) {
rmcptr->mc_type = LITSTRING;
if ((rmcptr->u.rstr = malloc(mj + 1)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
status = FALSE;
break;
}
bytecopy(rmcptr->u.rstr, patptr - mj, mj);
rmcptr++;
mj = 0;
}
rmcptr->mc_type = DITTO;
rmcptr++;
rmagical = TRUE;
break;
case MC_ESC:
pchr = *(patptr + 1); /* peek at next char.*/
if (pchr <= '9' && pchr >= '1') {
if (mj != 0) {
rmcptr->mc_type = LITSTRING;
if ((rmcptr->u.rstr = malloc(mj + 1)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
status = FALSE;
break;
}
bytecopy(rmcptr->u.rstr, patptr - mj, mj);
rmcptr++;
mj = 0;
}
rmcptr->mc_type = GROUP;
rmcptr->u.group_no = pchr - '0';
patptr++;
}
else
{
rmcptr->mc_type = LITSTRING;
/* We malloc mj plus two here, instead
* of one, because we have to count the
* current character.
*/
if ((rmcptr->u.rstr = malloc(mj + 2)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
status = FALSE;
break;
}
bytecopy(rmcptr->u.rstr, patptr - mj, mj + 1);
/* If MC_ESC is not the last character
* in the string, find out what it is
* escaping, and overwrite the last
* character with it.
*/
if (pchr != '\0') {
*((rmcptr->u.rstr) + mj) = pchr;
patptr++;
}
mj = 0;
}
rmcptr++;
rmagical = TRUE;
break;
default:
mj++;
}
patptr++;
}
if (rmagical && mj > 0) {
rmcptr->mc_type = LITSTRING;
if ((rmcptr->u.rstr = malloc(mj + 1)) == NULL) {
mlabort(TEXT94);
/* "%%Out of memory" */
status = FALSE;
}
bytecopy(rmcptr->u.rstr, patptr - mj, mj);
rmcptr++;
}
rmcptr->mc_type = MCNIL;
return (status);
}
/*
* rmcclear -- Free up any strings, and MCNIL the RMC array.
*/
VOID PASCAL NEAR rmcclear()
{
register RMC *rmcptr;
rmcptr = &rmcpat[0];
while (rmcptr->mc_type != MCNIL) {
if (rmcptr->mc_type == LITSTRING)
free(rmcptr->u.rstr);
rmcptr++;
}
rmcpat[0].mc_type = MCNIL;
}